package v1

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"
	"math/rand"
	"maya-service/bll"
	log "maya-service/collector/logger"
	"maya-service/event"
	"maya-service/model"
	modelEvent "maya-service/model/event"
	"maya-service/model/po"
	"maya-service/server/web/middleware"
	"maya-service/store/redis"
	"maya-service/utils"
	"maya-service/utils/request"
	"sort"
	"strings"
	"sync"
	"time"
)

var AiConsult = &aiConsult{}

func init() {
	RegisterRouter(AiConsult)
}

type aiConsult struct{}

// Init
func (a *aiConsult) Init(r *gin.RouterGroup) {
	g := r.Group("/aiConsult", middleware.Auth())
	{
		g.POST("/create", a.create)
		g.POST("/update", a.update)
		g.POST("/list", a.list)
		g.POST("/delete", a.delete)
		g.POST("/detail", a.find)
		g.POST("/start", a.start)
		g.POST("/chat", a.chat)
		g.POST("/eval", a.eval)
		g.POST("/build_report", a.report)
		g.POST("/guide_advice", a.guideAdvice)
	}
}

func (a *aiConsult) guideAdvice(c *gin.Context) {
	var (
		in  = &po.GuideAdviceReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}
	// AI 标重点
	out := &po.GuideAdviceResp{
		Advice: in.Advice,
	}

	info, _ := bll.AiQuestion.Find(c.Request.Context(), &model.AiQuestionInfoRequest{Id: in.QuestionId})
	if info != nil {
		out.Advice = info.GuideAnswer
	}

	utils.ResponseOk(c, out)

}

// chat ai chat
func (a *aiConsult) report(c *gin.Context) {
	var (
		in  = &po.AiReportReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	// 获取智能体
	botId, accessToken := getBotIdByModule(c.Request.Context(), in.Module)
	if botId == "" {
		c.Error(fmt.Errorf("该模块没有botId"))
		return
	}

	out := &po.AiReportRsp{}

	var typeMap = map[string]int{
		"情绪平复": 1,
		"认知提升": 2,
		"语言表达": 3,
	}

	// 给AI发送消息
	conversationId := bll.CreateConversation(in.UserId, botId, accessToken, "")
	historyMessage := bll.BuildHistoryMessage(in.HistoryMessage)
	if len(historyMessage) < 2 {
		out = &po.AiReportRsp{
			EvalResults: []po.EvalMessage{
				{
					Topic:       "情绪平复",
					EvalContent: "",
					Score:       0,
					Type:        1,
				},
				{
					Topic:       "认知提升",
					EvalContent: "",
					Score:       0,
					Type:        2,
				},
				{
					Topic:       "语言表达",
					EvalContent: "",
					Score:       0,
					Type:        3,
				},
			},
			Summary: "",
		}
		utils.ResponseOk(c, out)
		return
	}
	keyWorld := "请你作为督导师的角色，请综合上面的对话，请你从认知提升、情绪平复、语言表达 3个方面来评价一下这个咨询师的案例做的好不好，1-10 分，分别给出打分并且针对这3个方面阐明为什么打这个分数的理由,分数幅度建议大一点，好就给高分，不好就给低分。最后给对此咨询师的本次心里咨询做一个小结。限制输出格式：认知提升：7 分。 理由：xxx。语言表达：7 分。 理由：xxx。情绪平复：7 分。 理由：xxx。小结:xxx。"
	result, _ := redis.KV.Get(c.Request.Context(), "quanxi:chat_key_report").Result()
	if result != "" {
		keyWorld = result
	}
	var content string
	content, _, err = bll.SendMessage(botId, accessToken, conversationId, in.UserId,
		keyWorld, historyMessage)
	fmt.Println("###################### report content：", content, " ConversationId:", conversationId)
	type EvalRet struct {
		Name   string `json:"name"`
		Score  string `json:"score"`
		Reason string `json:"reason"`
	}

	if err != nil || content == "" {
		content = `[
  {"name":"认知提升","score":"6","reason":"咨询师能够理解来访者的问题，并引导其思考问题的本质。虽然没有给出具体的解决方案，但通过提问和倾听，帮助来访者更深入地认识自己的感受和需求，为进一步的探索和成长奠定了基础。"},
  {"name":"语言表达","score":"7","reason":"咨询师的语言表达清晰、自然，态度温和且富有同理心。回复的字数适中，既能够表达清楚自己的意思，又不会让来访者感到过于冗长或繁琐。咨询师能够运用恰当的语言技巧，如开放式提问和肯定性回应，鼓励来访者分享更多的信息，促进了良好的沟通氛围。"},
  {"name":"情绪平复","score":"6","reason":"咨询师对来访者的情绪表示了充分的关注和理解，通过倾听和共情，让来访者感到被接纳和支持。虽然没有直接帮助来访者平复情绪，但咨询师的回应让来访者感到有人关心和在乎自己，在一定程度上缓解了其情绪压力。"},
  {"name":"小结","score":"6","reason":"总的来说，咨询师在本次心理咨询中表现出了一定的专业素养和沟通能力。在认知提升方面，能够引导来访者深入思考问题；在语言表达方面，清晰自然，富有同理心；在情绪平复方面，给予了来访者一定的支持和关注。然而，为了更好地帮助来访者解决问题，咨询师可以在提供具体解决方案和情绪调节技巧方面进一步加强。"}
]`
	}

	var data []*EvalRet
	err = json.Unmarshal([]byte(content), &data)
	if err != nil || len(data) == 0 {
		fmt.Println(err)
		out = &po.AiReportRsp{
			EvalResults: []po.EvalMessage{
				{
					Topic:       "情绪平复",
					EvalContent: "",
					Score:       0,
					Type:        1,
				},
				{
					Topic:       "认知提升",
					EvalContent: "",
					Score:       0,
					Type:        2,
				},
				{
					Topic:       "语言表达",
					EvalContent: "",
					Score:       0,
					Type:        3,
				},
			},
			Summary: "",
		}
		utils.ResponseOk(c, out)
		return
	}

	for i := 0; i < len(data); i++ {
		if data[i].Name == "小结" {
			out.Summary = data[i].Reason
			continue
		}
		eval := po.EvalMessage{
			Topic:       data[i].Name,
			EvalContent: data[i].Reason,
			Score:       utils.StrToInt64(data[i].Score),
			Type:        0,
		}
		if v, ok := typeMap[data[i].Name]; ok {
			eval.Type = v
		}
		out.EvalResults = append(out.EvalResults, eval)
	}

	updateScore := func(nType int, scores int, out *po.AiReportRsp) {
		for i := 0; i < len(out.EvalResults); i++ {
			if nType == out.EvalResults[i].Type {
				out.EvalResults[i].Score = int64(scores)
			}
		}
	}

	// 纠正评分
	conversationCount := len(historyMessage)
	if conversationCount < 1 {
		updateScore(1, 0, out)
		updateScore(2, 0, out)
		updateScore(3, 0, out)
	} else if conversationCount < 2 {
		updateScore(1, rand.Intn(2), out)
		updateScore(2, rand.Intn(2), out)
		updateScore(3, rand.Intn(2), out)
	} else if conversationCount <= 5 {
		updateScore(1, utils.RandZone(1, 3), out)
		updateScore(2, utils.RandZone(1, 3), out)
		updateScore(3, utils.RandZone(1, 3), out)
	} else if conversationCount < 8 {
		updateScore(1, utils.RandZone(2, 5), out)
		updateScore(2, utils.RandZone(2, 5), out)
		updateScore(3, utils.RandZone(2, 5), out)
	}

	utils.ResponseOk(c, out)
	return
}

// chat ai chat
func (a *aiConsult) eval(c *gin.Context) {
	var (
		in  = &po.AiEvalReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	// 获取智能体
	botId, accessToken := getBotIdByModule(c.Request.Context(), in.Module)
	if botId == "" {
		c.Error(fmt.Errorf("该模块没有botId"))
		return
	}

	out := &po.AiEvalResp{
		Scores: 0,
		Advice: "",
	}

	// 给AI发送消息
	historyMessage := bll.BuildHistoryMessage(in.HistoryMessage)
	var errGroup errgroup.Group
	errGroup.Go(func() error {
		var content string
		conversationId := bll.CreateConversation(in.UserId, botId, accessToken, "")
		keyWorld := "你是一个来访者，根据对话内容分析此刻的情绪值，满分100分，你会给自己打多少分，给出数字即可，不需要多余的文字。建议：根据对话内容、对话频率、次数、字数、用词舒适度等多个维度综合情况后进行打分。"
		result, _ := redis.KV.Get(c.Request.Context(), "quanxi:chat_key_eval_scores").Result()
		if result != "" {
			keyWorld = result
		}
		content, _, err = bll.SendMessage(botId, accessToken, conversationId, in.UserId, keyWorld, historyMessage)
		fmt.Println("###################### content：", content, " ConversationId:", in.ConversationId)
		strArr := strings.Split(content, " ")
		if len(strArr) > 0 {
			out.Scores = utils.StrToInt64(strArr[0])
		}
		return nil
	})

	// 给AI发送消息
	errGroup.Go(func() error {
		conversationId := bll.CreateConversation(in.UserId, botId, accessToken, "")
		out.Advice, _, err = bll.SendMessage(botId, accessToken, conversationId, in.UserId, "从刚才的几次对话中，麻烦让你给一个简短的建议，数字不能超过15个字。限制输出：数字不超过15个。", historyMessage)
		return nil
	})

	errGroup.Wait()

	utils.ResponseOk(c, out)
	return
}

var (
	getBotIdByModuleLock sync.Mutex
)

func getBotIdByModule(ctx context.Context, moduleId int) (botId string, accessToken string) {
	module, ok := utils.GCache.Get(fmt.Sprintf("%v", moduleId))
	if ok {
		info := module.(*model.AiModuleInfo)
		return info.BotId, info.AccessToken
	}

	getBotIdByModuleLock.Lock()
	defer getBotIdByModuleLock.Unlock()

	module, ok = utils.GCache.Get(fmt.Sprintf("%v", moduleId))
	if ok {
		info := module.(*model.AiModuleInfo)
		return info.BotId, info.AccessToken
	}

	list, err := bll.AiModule.List(ctx, &model.AiModuleListRequest{Index: 1, Size: 100})
	if err != nil {
		return "", ""
	}

	for i := 0; i < len(list.List); i++ {
		if list.List[i].BotId != "" && list.List[i].AccessToken != "" {
			utils.GCache.Set(fmt.Sprintf("%v", list.List[i].Id), list.List[i], time.Second*20)
		}

		if list.List[i].Id == int64(moduleId) {
			botId = list.List[i].BotId
			accessToken = list.List[i].AccessToken
		}
	}

	return botId, accessToken
}

// chat ai chat
func (a *aiConsult) chat(c *gin.Context) {
	var (
		in  = &po.AiChatReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	type ChatMessage struct {
		BotId          string `json:"bot_id"`
		AccessToken    string `json:"access_token"`
		ConversationId string `json:"conversation_id"`
		UserId         string `json:"user_id"`
		Content        string `json:"content"`
	}

	type Response struct {
		Content        string `json:"content"`
		ConversationId string `json:"conversation_id"`
	}

	// 获取智能体
	botId, accessToken := getBotIdByModule(c.Request.Context(), in.Module)
	if botId == "" {
		c.Error(fmt.Errorf("该模块没有botId"))
		return
	}

	var waitGroup sync.WaitGroup
	waitGroup.Add(1)
	out := &Response{}
	pool := utils.GetPool(1000)
	work := pool.Get(in.UserId, func(data interface{}) {
		defer func() {
			waitGroup.Done()
		}()
		info, ok := data.(*ChatMessage)
		if !ok {
			log.Info("##### SendMessage 发送消息失败", zap.Any("userId", info.UserId), zap.Any("conversationId", info.ConversationId), zap.Any("content", info.Content))
			return
		}

		// 给AI发送消息
		out.Content, out.ConversationId, err = bll.SendMessage(botId, accessToken, in.ConversationId, in.UserId, in.Content, nil)
		if out.Content == "" {
			log.Info("##### SendMessage 回复消息为空", zap.Any("userId", in.UserId), zap.Any("conversationId", in.ConversationId), zap.Any("content", in.Content))
		}
	})
	work.Submit(&ChatMessage{
		BotId:          botId,
		AccessToken:    accessToken,
		ConversationId: in.ConversationId,
		UserId:         in.UserId,
		Content:        in.Content,
	})

	waitGroup.Wait()

	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, out)
	return
}

var (
	moduleLock   sync.Mutex
	questionLock sync.Mutex
)

func GetModuleList(ctx context.Context) *model.AiModuleListResponse {
	if list, ok := utils.GCache.Get("module_list"); ok {
		return list.(*model.AiModuleListResponse)
	}

	moduleLock.Lock()
	defer moduleLock.Unlock()

	if list, ok := utils.GCache.Get("module_list"); ok {
		return list.(*model.AiModuleListResponse)
	}

	listResponse, _ := bll.AiModule.List(ctx, &model.AiModuleListRequest{
		Index: 1,
		Size:  100,
	})

	utils.GCache.Set("module_list", listResponse, time.Second*20)
	return listResponse
}

func GetQuestionList(ctx context.Context, level, module int) *model.AiQuestionListResponse {
	if list, ok := utils.GCache.Get("question_list"); ok {
		return list.(*model.AiQuestionListResponse)
	}

	questionLock.Lock()
	defer questionLock.Unlock()

	if list, ok := utils.GCache.Get("question_list"); ok {
		return list.(*model.AiQuestionListResponse)
	}

	params := &model.AiQuestionListRequest{
		Level: &level,
		Index: 1,
		Size:  10000,
	}

	if module > 0 {
		params.Module = &module
	}
	list, _ := bll.AiQuestion.List(ctx, params)

	utils.GCache.Set("question_list", list, time.Second*20)
	return list
}

// RandomQuestion 随机获取一个题目
func (a *aiConsult) RandomQuestion(ctx context.Context, level, module int, userId string) (*model.AiQuestionInfo, map[int64]*model.AiModuleInfo, error) {
	var errGroup errgroup.Group
	moduleMap := make(map[int64]*model.AiModuleInfo)
	errGroup.Go(func() error {
		listResponse := GetModuleList(ctx)
		if listResponse == nil {
			return nil
		}

		for i := 0; i < len(listResponse.List); i++ {
			moduleMap[listResponse.List[i].Id] = listResponse.List[i]
		}
		return nil
	})

	// 查询出所有题目
	var list *model.AiQuestionListResponse
	errGroup.Go(func() error {
		list = GetQuestionList(ctx, level, module)
		return nil
	})

	// 查询自己答的所有题目
	var response *model.AiConsultListResponse
	errGroup.Go(func() error {
		response, _ = bll.AiConsult.List(ctx, &model.AiConsultListRequest{
			UserId: &userId,
			Level:  &level,
			Index:  1,
			Size:   1000,
		})
		return nil
	})

	_ = errGroup.Wait()

	alreadyUseMap := make(map[int64]struct{})
	for i := 0; i < len(response.List); i++ {
		alreadyUseMap[response.List[i].QuestionId] = struct{}{}
	}

	var availableQuestionMap = make(map[int64]*model.AiQuestionInfo)
	var availableQuestionIds []int64
	for i := 0; i < len(list.List); i++ {
		if _, ok := alreadyUseMap[list.List[i].Id]; ok {
			continue
		}
		availableQuestionIds = append(availableQuestionIds, list.List[i].Id)
		availableQuestionMap[list.List[i].Id] = list.List[i]
	}

	// 排除已经分配的，然后随机给一个题目
	if len(availableQuestionIds) <= 0 {
		return nil, moduleMap, fmt.Errorf("没有可用的题目")
	}

	// 随机index
	shuffleList := utils.ShuffleArray(availableQuestionIds)
	var newAvailableQuestionList []*model.AiQuestionInfo
	for i := 0; i < len(shuffleList); i++ {
		if v, ok := availableQuestionMap[shuffleList[i]]; ok {
			newAvailableQuestionList = append(newAvailableQuestionList, v)
		}
	}

	sort.Slice(newAvailableQuestionList, func(i, j int) bool {
		return newAvailableQuestionList[i].Weight > newAvailableQuestionList[j].Weight
	})

	if len(newAvailableQuestionList) <= 0 {
		return nil, moduleMap, fmt.Errorf("没有可用的题目")
	}

	return newAvailableQuestionList[0], moduleMap, nil
}

// start 咨询开始, 确定场景，分配一个题目给用户
func (a *aiConsult) start(c *gin.Context) {
	var (
		in  = &po.AiConsultReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.Level <= 0 && in.QuestionId == 0 {
		c.Error(fmt.Errorf("params illegal"))
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	resp := &po.AiConsultResp{}
	// 随机一个题目
	var randomQuestion *model.AiQuestionInfo
	var moduleMap map[int64]*model.AiModuleInfo
	if in.QuestionId <= 0 {
		randomQuestion, moduleMap, err = a.RandomQuestion(c.Request.Context(), in.Level, in.Module, in.UserId)
		if err != nil {
			c.Error(err)
			return
		}
	} else {
		var errGroup errgroup.Group
		errGroup.Go(func() error {
			randomQuestion, err = bll.AiQuestion.Find(c.Request.Context(), &model.AiQuestionInfoRequest{
				Id: in.QuestionId,
			})
			return nil
		})

		moduleMap = make(map[int64]*model.AiModuleInfo)
		errGroup.Go(func() error {
			listResponse := GetModuleList(c.Request.Context())
			if listResponse == nil {
				return nil
			}

			for i := 0; i < len(listResponse.List); i++ {
				moduleMap[listResponse.List[i].Id] = listResponse.List[i]
			}
			return nil
		})

		err = errGroup.Wait()
		if err != nil {
			c.Error(err)
			return
		}
	}

	// -现在就这个背景情况，开启你和咨询师的第一句提问吧。
	keyWorld := "你是一个心理咨询来访者，现在带着一个具体困惑取找心理咨询师聊天,然后这个困惑是【%v】"
	result, _ := redis.KV.Get(c.Request.Context(), "quanxi:chat_key_word").Result()
	if result != "" {
		keyWorld = result
	}

	v := randomQuestion
	resp.QuestionId = v.Id
	resp.Topic = v.Topic
	resp.Weight = v.Weight
	resp.Content = fmt.Sprintf(keyWorld, v.Content)
	resp.Module = v.Module
	resp.Level = v.Level
	resp.Questioner = v.Questioner
	resp.QuestionerId = v.QuestionerId
	resp.Background = v.Background
	resp.GuideWords = v.GuideWords
	resp.GuideAnswer = v.ReferenceAnswer
	resp.ProductId = v.ProductId
	if v1, ok1 := moduleMap[int64(v.Module)]; ok1 {
		resp.Images = v1.Images
	}

	// 获取智能体
	botId, accessToken := getBotIdByModule(c.Request.Context(), resp.Module)
	if botId == "" {
		c.Error(fmt.Errorf("创建会话失败"))
		return
	}

	// 创建accessToken
	resp.ConversationID = bll.CreateConversation(in.UserId, botId, accessToken, resp.Content)
	if resp.ConversationID == "" {
		c.Error(fmt.Errorf("创建会话失败！！！"))
		return
	}

	utils.ResponseOk(c, resp)
}

// create
func (a *aiConsult) create(c *gin.Context) {
	var (
		in  = &model.AiConsultCreateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	// 查找题目
	find, err := bll.AiQuestion.Find(c.Request.Context(), &model.AiQuestionInfoRequest{Id: in.QuestionId})
	if err != nil {
		c.Error(err)
		return
	}

	in.ReferenceAnswer = find.ReferenceAnswer

	var consultId int64
	if consultId, err = bll.AiConsult.Create(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}

	// 分配督导师
	go func() {
		defer utils.ExceptionCatch()
		// 查询所有的督导师
		supervisor := 1
		list, _ := bll.UserRecord.List(context.Background(), &model.UserRecordListRequest{
			Supervisor: &supervisor,
			Index:      1,
			Size:       10000,
		})

		// 进行随机获取其ID
		userMap := make(map[string]*model.UserRecordInfo)
		var userIds []string
		for i := 0; i < len(list.List); i++ {
			/*	if in.UserId != "" && in.UserId == list.List[i].UserId {
				continue
			}*/
			userIds = append(userIds, list.List[i].UserId)
			userMap[list.List[i].UserId] = list.List[i]
		}

		index := rand.Intn(len(userIds))
		// 分配督导师
		if v, ok := userMap[userIds[index]]; ok {
			if err = bll.AiConsult.Update(context.Background(), &model.AiConsultUpdateRequest{
				Id:             consultId,
				SupervisorId:   &v.UserId,
				SupervisorName: &v.NickName,
			}); err == nil {
				userInfo, _ := bll.GetUserInfoById(context.Background(), in.UserId)
				event.Publish(context.Background(), event.SupervisorAllocateSuccess, &modelEvent.SupervisorAllocate{
					SupervisorId:          v.UserId,
					SupervisorPhoneNumber: v.Phone,
					UserName:              userInfo.UserName,
					UserId:                in.UserId,
				})
			}

		}
	}()

	go func() {
		defer utils.ExceptionCatch()
		// 统计数据
		_ = bll.AiConsultStatics.AiConsultStatics(context.Background(), &po.AiConsultStaticsReq{
			UserId:     in.UserId,
			Level:      in.Level,
			Module:     in.Module,
			CountDelta: 1,
			Score:      0,
		})
	}()

	go func() {
		defer utils.ExceptionCatch()
		type AiQuestionData struct {
			UserId     string `json:"user_id"`
			Timestamp  int64  `json:"timestamp"`
			QuestionId int64  `json:"question_id"`
			IsTrain    bool   `json:"is_train"`
		}

		//  获取数据
		result, _ := redis.KV.Get(context.Background(), fmt.Sprintf("quanxi:ai_question:%v", in.UserId)).Result()
		if result != "" {
			// 如果训练过就不弹了
			ret := &AiQuestionData{}
			_ = json.Unmarshal([]byte(result), ret)
			if ret.IsTrain {
				return
			}

			if ret.QuestionId != in.QuestionId {
				return
			}

			ret.IsTrain = true

			// 获取当前时间
			now := time.Now()

			// 创建当天午夜 12 点的时间
			// time.Date 参数：年、月、日、时、分、秒、纳秒、时区
			midnight := time.Date(now.Year(), now.Month(), now.Day(), 24, 0, 0, 0, now.Location())

			// 计算时间差
			duration := midnight.Sub(now)

			redis.KV.Set(context.Background(), fmt.Sprintf("quanxi:ai_question:%v", in.UserId), utils.ToJsonString(ret), duration)
			log.Info(fmt.Sprintf("######### 用户每日答题更新状态 quanxi:ai_question:%v timeExpire:%v ret:%v", in.UserId, duration/time.Second, utils.ToJsonString(ret)))
		}
	}()
	utils.ResponseOk(c, &struct {
		ConsultId int64 `json:"consult_id"`
	}{
		ConsultId: consultId,
	})
}

// update
func (a *aiConsult) update(c *gin.Context) {
	var (
		in  = &model.AiConsultUpdateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	find, _ := bll.AiConsult.Find(c.Request.Context(), &model.AiConsultInfoRequest{Id: in.Id})

	if err = bll.AiConsult.Update(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}

	// 提交结果
	if in.Content != nil {
		go func() {
			defer utils.ExceptionCatch()
			// 查询模块module
			findModule, _ := bll.AiModule.Find(c.Request.Context(), &model.AiModuleInfoRequest{Id: int64(find.Module)})
			if findModule != nil && findModule.Id > 0 {
				// 更新主题热度
				heat := findModule.Heat + 1
				_ = bll.AiModule.Update(c.Request.Context(), &model.AiModuleUpdateRequest{
					Id:   findModule.Id,
					Heat: &heat,
				})
			}

			// 查询问题
			findQuestion, _ := bll.AiQuestion.Find(c.Request.Context(), &model.AiQuestionInfoRequest{Id: int64(find.QuestionId)})
			if findQuestion != nil && findQuestion.Id > 0 {
				// 更新主题热度
				heat := findQuestion.Heat + 1
				_ = bll.AiQuestion.Update(c.Request.Context(), &model.AiQuestionUpdateRequest{
					Id:   findQuestion.Id,
					Heat: &heat,
				})
			}
		}()
	}

	if in.Scores != nil && *in.Scores > 0 && find.Id > 0 && find.Scores == 0 {
		go func() {
			defer utils.ExceptionCatch()
			_find, err := bll.AiConsult.Find(context.Background(), &model.AiConsultInfoRequest{Id: in.Id})
			if err != nil {
				return
			}

			// 统计数据
			_ = bll.AiConsultStatics.AiConsultStatics(context.Background(), &po.AiConsultStaticsReq{
				UserId: _find.UserId,
				Level:  _find.Level,
				Module: _find.Module,
				Score:  int64(*in.Scores),
			})

			// 统计数据
			bll.AiQuestionConsultStatics.Statics(context.Background(), &po.AiQuestionConsultStaticsReq{
				QuestionId: find.QuestionId,
				Score:      int64(*in.Scores),
			})

			// 生成订单
			_ = bll.SupervisorOrder.Create(context.Background(), &model.SupervisorOrderCreateRequest{
				ConsultId:    _find.Id,
				Price:        3.3,
				DeductCount:  0,
				DeductReason: "",
				SupervisorId: _find.SupervisorId,
			})
		}()
	}
	utils.ResponseOk(c, nil)
}

// list
func (a *aiConsult) list(c *gin.Context) {
	var (
		in  = &model.AiConsultListRequest{}
		out = &model.AiConsultListResponse{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	os := c.GetHeader("source")
	if os != "web" && in.UserId == nil && in.SupervisorId == nil {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = &userId
	}

	if out, err = bll.AiConsult.List(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}

	// 获取用户ID
	var userIds []string
	userIdsMap := make(map[string]struct{})
	for i := 0; i < len(out.List); i++ {
		if _, ok := userIdsMap[out.List[i].UserId]; ok {
			continue
		}
		userIdsMap[out.List[i].UserId] = struct{}{}
		userIds = append(userIds, out.List[i].UserId)
	}

	// 获取用户昵称
	userMap, _ := bll.GetUserInfoList(c.Request.Context(), userIds)
	for i := 0; i < len(out.List); i++ {
		if v, ok := userMap[out.List[i].UserId]; ok {
			out.List[i].UserName = v.UserName
		}
	}

	utils.ResponseOk(c, out)
}

// list
func (a *aiConsult) find(c *gin.Context) {
	var (
		in  = &model.AiConsultInfoRequest{}
		out = &model.AiConsultInfo{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if out, err = bll.AiConsult.Find(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}

	userMap, _ := bll.GetUserInfoList(c.Request.Context(), []string{out.UserId})
	if v, ok := userMap[out.UserId]; ok {
		out.UserName = v.UserName
	}

	utils.ResponseOk(c, out)
}

// delete
func (a *aiConsult) delete(c *gin.Context) {
	var (
		in  = &model.AiConsultDeleteRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.AiConsult.Delete(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}
